/*
 *  \file AlgorithmFunctions.h
 *  GRE
 *
 *  Created by Kutlak Roman on 28/08/2011.
 *  Copyright 2011 University of Aberdeen. All rights reserved.
 *
 */

#ifndef AlgorithmFunctions_h 
#define AlgorithmFunctions_h

#include "Ontology.h"
#include "RefExp.h"
#include "KnowledgeBase.h"

namespace kutlak {
namespace roman {
namespace gre {

    /*!
     * \brief A set of functions for GRE algorithms.
     */
    
    typedef std::vector<EntityPtrT> ContainerT;
    
    
#pragma mark -
#pragma mark predicates
    
    struct HasPropertyPred
    {
        HasPropertyPred(Property p) : property_(p) {}
        
        bool operator()(EntityPtrT e)
        { return (e->HasProperty(property_)); }
        
    private:
        Property property_;
    };
    
    struct DoesNotHavePropertyPred
    {
        DoesNotHavePropertyPred(Property p) : property_(p) {}
        
        bool operator()(EntityPtrT e)
        { return !(e->HasProperty(property_)); }
        
    private:
        Property property_;
    };
    
    
    struct DoesNotHaveValuePred
    {
        DoesNotHaveValuePred(Property p) : property_(p) {}
        
        bool operator()(EntityPtrT e)
        {
            return (e->HasAttribute(property_.Attribute()) && 
                    !e->HasProperty(property_) );
        }
        
    private:
        Property property_;
    };
    
    
    struct DoesNotHavePropertiesPred
    {
        DoesNotHavePropertiesPred(RefExp re) : re_(re) {}
        
        bool operator()(EntityPtrT e)
        {
            for (auto it : re_)
                if (!e->HasProperty(it))
                    return true;

            return false;
        }
        
    private:
        RefExp re_;
    };
    

#pragma mark -
#pragma mark comparators
    
    struct SubsumptionComparator
    {
        explicit SubsumptionComparator(const pOntology& o) : onto(o) {}
        
        bool operator()(const std::pair<Property, double>& first, 
                        const std::pair<Property, double>& second)
        { return (onto->Subsumes(first.first, second.first)); }
        
    private:
        pOntology onto;
    };
    
    
    /*! \brief Comparator for paired values.
     */
    template <class T, class U>
    struct PairComparator
    {
        PairComparator(bool compareOnFirst = false)
        { fFirst = compareOnFirst; }
        
        bool operator()(const std::pair<T, U>& lhs, const std::pair<T, U>& rhs)
        {
            if (fFirst)
                return (lhs.first < rhs.first);
            else
                return (lhs.second < rhs.second);
        }
        
    private:
        bool fFirst;
    };
    
#pragma mark -
#pragma mark functions
    
    /*! \brief Method counts how many entities in a KnowledgeBase do not have given property.
     \param property the property that is being tested.
     \param distractors the KnowledgeBase of entities that serve as potential distractors.
     \return number of entities that do not have the property.
     */
    int RulesOut(const ContainerT& distractors,
                 const Property& property);
    
    int Filter(ContainerT& distractors,
               const EntityPtrT& entity);
    
    /*! \brief Method filters out entities that do not have given property.
     \param property the property used as a filter.
     \param distractors a KnowledgeBase of entities that serve as potential distractors.
     \return number of removed entities.
     */
    int Filter(ContainerT& distractors,
               const Property& property);
    
    /*! \brief Same as filter but does not remove entity if it does not have the attribute
     *  regardless of the value.
     */
    int SoftFilter(ContainerT& distractors,
                   const Property& property);
    
    /*! \brief Method calculates the discriminatory power of a property wrt to the given set.
     \param property is the property whose discriminatory power is being calculated.
     \param distractors is the KnowledgeBase of distracting entities.
     \param m number of referents. This is usually one but allows for plural.
     \return the discriminatory power of the property. Value between 0.0 and 1.0.
     *  The value of 1.0 means that the property removes all entities in the container.
     *  The value of 0.0 means that the property removes none of the entities in the container.
     *  The value is calculated as N-n/N-m
     *  where N is the number of entities being considered
     *  and n is number of entities having the property
     *  and m is the number of entities being singled out
     *  (m = 0 if the referent is not in the distractor set, m = 1 for one referent and so on)
     */
    double DiscriminatoryPower(const ContainerT& distractors,
                               const Property& property, 
                               const int m = 0);
    
    /*! Mehtod checks if a property has any discriminatory power.
     *  This boils down to test of whether there is at leas one entity that does not
     *  have the given property. 
     */
    bool HasDiscriminatoryPower(const ContainerT& distractors,
                                const Property& property);
    
    
    
    /*! \brief This mehtod counts how many objects from the set the expression refers to
     *
     * Extension is in the logic sense - all elements of a set that have the properties
     * specified by the expression (boolean AND operation across properties assumed).
     * \param re referring expression (list of properties) whose extension we want to know
     * \param distractors is the list of entities from which the extension will be derived
     * \return container with entities that have all the properties specified by re
     */
    ContainerT Extension(ContainerT distractors,
                         const RefExp& re);
    
    
    //! Returns the size of the extension created by the given RE.
    size_t ExtensionSize(const ContainerT& distractors,
                         const RefExp& re);
    
    ContainerT Extension(ContainerT distractors, 
                         const Property& p);
    
    size_t ExtensionSize(const ContainerT& distractors,
                         const Property& p);
    
    /*! \brief Method finds the best value for the current property.
     \param referent is the referent of the expression
     \param distractors is the set of all entities in the domain
     \param property is the examined property for which we need to find the best value
     \return the best available value for the attribute given by the property.
     *  The best value is the one which removes the most distractors from the set. Ideally
     *  the value would also be the most generall one or even better the basic level category
     *  as explained in Rosch 1978. The basic level values are really difficult to find even wehn 
     *  an ontology is available. For example DBPedia will give the value "eukaryote" as the basic type
     *  for a plant as it is directly below owl:Thing. But persumably Plant is the value we would like.
     *  One possible way of improving this would be to have mappings between every property in the ontology
     *  and its surface string and use a corpus to determine the most common term.
     *
     *  The method uses the Ontology only when it is actually set. In case where the ontology is not used
     *  the algorithm goes through all the properties that have the same attribute as the currently 
     *  inspected property and picks the most discriminatory value. There are no guaranties as to how 
     *  specific the value is so even when all values have the same discriminatoyr power the method just
     *  returns one of them regardles of whether it is the most or the least specific.
     *
     *  Note that if the referent does not have the specified property, it is this property that
     *  will be returned as the best level value.
     */
    Property FindBestValue(const ContainerT& distractors,
                           const EntityPtrT& referent,  
                           const Property& property);
} // end namespace gre
}
}
#endif // AlgorithmFunctions_h
